package panicsafe

import (
	"fmt"
	"os"
	"sync/atomic"
	"time"
)

var (
	panicLogPath    string
	panicFilePrefix string
	panicIdx        int32
)

// 获取发生Panic异常的次数
func GetPanicCounter() int {
	return int(atomic.LoadInt32(&panicIdx))
}

func EnablePanicRecordFile(logPath, prefix string) {
	GoFunCatchException = true
	OnCatchAllPanic = panicRecordFile

	exeName := os.Args[0] //获取程序名称
	exeName = ExtractFileNameWithOutPathAndExt(exeName)
	dumpName := os.Getenv("DUMPFILEID")
	if len(dumpName) > 0 {
		exeName = dumpName
	} else {
		hostName := os.Getenv("HOSTNAME")
		if len(hostName) > 0 {
			exeName = fmt.Sprintf("%s-%s", exeName, hostName)
		}
	}

	panicLogPath = logPath
	if len(panicLogPath) > 0 {
		if panicLogPath[len(panicLogPath)-1] == '/' || panicLogPath[len(panicLogPath)-1] == '\\' {

		} else {
			panicLogPath = fmt.Sprintf("%s%s", panicLogPath, PathSeparator)
		}
		ForceCreatePath(panicLogPath)
	}
	panicFilePrefix = fmt.Sprintf("%s%s-%d-%s", panicLogPath, exeName, os.Getpid(), prefix)
}

func panicRecordFile(err interface{}, args ...interface{}) {
	now := time.Now() //获取当前时间
	uid := atomic.AddInt32(&panicIdx, 1)
	datestr := now.Format("20060102")
	nowstrEx := now.Format("2006-01-02 15:04:05.999")
	//设定时间格式
	fname := fmt.Sprintf("%s-%s-%d.log", panicFilePrefix, datestr, uid) //保存错误信息文件名:程序名-进程ID-当前时间（年月日时分秒）

	datastr := ""

	if len(args) > 0 {
		if str, ok := args[0].(string); ok {
			datastr = str
		} else if fn, ok1 := args[0].(func() string); ok1 {
			datastr = fn()
		} else if fn2, ok2 := args[0].(func() interface{}); ok2 {
			v0 := fn2()
			datastr, _ = v0.(string)
		}
	}

	callStacks := string(GetCallStacks(3))

	f, err2 := os.OpenFile(fname, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660)
	if err2 != nil {
		fmt.Fprintln(os.Stderr, "save panic data fail:", err2)
		fmt.Fprintln(os.Stderr, "panic err:", err)
		if len(datastr) > 0 {
			fmt.Fprintf(os.Stderr, "%s\r\n", datastr)
		}
		fmt.Fprintf(os.Stderr, "[%s]panic stack:%s\r\n", nowstrEx, callStacks) //输出堆栈信息
		return
	}
	defer f.Close()
	fmt.Println("save panic to file: ", fname)
	if len(datastr) > 0 {
		f.WriteString(fmt.Sprintf("%s\r\n", datastr))
	}
	f.WriteString(fmt.Sprintf("[%s]:%v\r\n", nowstrEx, err)) //输出panic信息
	f.WriteString("---------------------------------------------\r\n")
	f.WriteString(callStacks) //输出堆栈信息
}
